home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 25: Programming / pc_actual_25.iso / Delphi / MP3 Blade Encoder Component 1.0 / MMBLADE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-05-06  |  16.3 KB  |  522 lines

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Fax.: +49 (0)351-8037944              =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 19.03.99 - 18:54:27 $                                        =}
  24. {========================================================================}
  25. unit MMBlade;
  26.  
  27. {$I COMPILER.INC}
  28.  
  29. interface
  30.  
  31. uses
  32. {$IFDEF WIN32}
  33.   Windows,
  34. {$ELSE}
  35.   WinTypes,
  36.   WinProcs,
  37. {$ENDIF}
  38.   SysUtils,
  39.   Classes,
  40.   Controls,
  41.   Dialogs,
  42.   MMSystem,
  43.   MMRegs,
  44.   MMObj,
  45.   MMDSPobj,
  46.   MMUtils,
  47.   MMWave,
  48.   BladeEnc;
  49.  
  50. type
  51.     TMMChannelMode = (cmStereo, cmDualChannel, cmMono);
  52.     TMMBitrates    = (br32,br40,br48,br56,br64,br80,br96,br112,
  53.                       br128,br160,br192,br224,br256,br320);
  54.     TMMFileType    = (ftWAV,ftRAW);
  55.  
  56.     {-- TMMMP3Encoder ---------------------------------------------------------}
  57.     TMMMP3Encoder  = class(TMMDSPComponent)
  58.     private
  59.        FWave       : TMMWave;
  60.        FHandle     : integer;
  61.        FOpen       : Boolean;
  62.        FStarted    : Boolean;
  63.        FFileName   : string;
  64.        FChannelMode: TMMChannelMode;
  65.        FBitrate    : TMMBitrates;
  66.        FCopyright  : Boolean;
  67.        FPrivate    : Boolean;
  68.        FCRC        : Boolean;
  69.        FOriginal   : Boolean;
  70.        FInSamples  : DWORD;
  71.        FInBufSize  : DWORD;
  72.        FInBuffer   : PChar;
  73.        FOutBufSize : DWORd;
  74.        FOutBuffer  : PChar;
  75.        FBytesQueued: Longint;
  76.        FHStream    : HBE_STREAM;
  77.        FFileType   : TMMFileType;
  78.  
  79.        procedure SetFileName(aValue: string);
  80.        procedure SetFileType(aValue: TMMFileType);
  81.  
  82.        function  _CreateFile: Boolean;
  83.        procedure _CloseFile;
  84.        function  _WriteFile(Buffer: PChar; nBytes: Longint): Boolean;
  85.  
  86.     protected
  87.        procedure Opened; override;
  88.        procedure Closed; override;
  89.        procedure Started; override;
  90.        procedure Stopped; override;
  91.        procedure BufferReady(lpwh: PWaveHdr); override;
  92.  
  93.     public
  94.        constructor Create(aOwner: TComponent); override;
  95.        destructor  Destroy; override;
  96.  
  97.     published
  98.        property Input;
  99.        property ChannelMode: TMMChannelMode read FChannelMode write FChannelMode default cmStereo;
  100.        property Bitrate: TMMBitrates read FBitrate write FBitrate default br128;
  101.        property Copyright: Boolean read FCopyright write FCopyright default False;
  102.        property Privat: Boolean read FPrivate write FPrivate default False;
  103.        property CRC: Boolean read FCRC write FCRC default False;
  104.        property Original: Boolean read FOriginal write FOriginal default False;
  105.        property FileName: string read FFileName write SetFileName;
  106.        property FileType: TMMFileType read FFileType write SetFileType default ftRAW;
  107.     end;
  108.  
  109. procedure Register;
  110.  
  111. implementation
  112.  
  113. const
  114.    CM : array[0..2] of Word = (BE_MP3_MODE_STEREO,BE_MP3_MODE_DUALCHANNEL,BE_MP3_MODE_MONO);
  115.    BR : array[TMMBitrates] of Word = (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320);
  116.  
  117. procedure Register;
  118. begin
  119.    RegisterComponents('MMWave', [TMMMP3Encoder]);
  120. end;
  121.  
  122. {========================================================================}
  123. function acmBuildMP3Header(SampleRate, Bitrate, Channels: integer): PWaveFormatEx;
  124. const
  125.     MP3Ext: array[0..11] of Byte = ($01,$00,$02,$00,$00,$00,$00,$00,$01,$00,$71,$05);
  126. var
  127.     BlockAlign: Double;
  128. begin
  129.     Result := GlobalAllocMem(sizeOf(TWaveFormatEx)+12);
  130.     with Result^ do
  131.     begin
  132.        wFormatTag     := WAVE_FORMAT_MPEG_LAYER3;
  133.        nChannels      := Channels;
  134.        nSamplesPerSec := SampleRate;
  135.        wBitsPerSample := 0;
  136.        nBlockAlign    := 1;
  137.        BlockAlign     := (144 * BitRate) / SampleRate;
  138.        nAvgBytesPerSec:= Round((((SampleRate*100) / 1152)*BlockAlign) / 100);
  139.        cbSize         := sizeOf(MP3Ext);
  140.        GlobalMoveMem(MP3Ext,(PChar(Result)+sizeOf(TWaveFormatEx))^,sizeOf(MP3Ext));
  141.        PWord(PChar(Result)+sizeOf(TWaveFormatEx)+6)^ := Trunc(BlockAlign);
  142.     end;
  143. end;
  144.  
  145. {== TMMMP3Encoder =============================================================}
  146. constructor TMMMP3Encoder.Create(aOwner: TComponent);
  147. begin
  148.    inherited Create(aOwner);
  149.  
  150.    FHandle      := 0;
  151.    FFileName    := '';
  152.    FOpen        := False;
  153.    FBitrate     := br128;
  154.    FChannelMode := cmStereo;
  155.    FCopyright   := False;
  156.    FPrivate     := False;
  157.    FCRC         := False;
  158.    FOriginal    := False;
  159.    FOutBuffer   := nil;
  160.    FInBuffer    := nil;
  161.    FFileType    := ftRAW;
  162.  
  163.    FWave        := TMMWave.Create;
  164. end;
  165.  
  166. {-- TMMMP3Encoder -------------------------------------------------------------}
  167. destructor TMMMP3Encoder.Destroy;
  168. begin
  169.    Closed;
  170.  
  171.    FWave.Free;
  172.  
  173.    inherited Destroy;
  174. end;
  175.  
  176. {-- TMMMP3Encoder -------------------------------------------------------------}
  177. procedure TMMMp3Encoder.SetFileName(aValue: string);
  178. begin
  179.    if (aValue <> FFileName) then
  180.    begin
  181.       if FOpen then
  182.          raise Exception.Create(LoadResStr(IDS_PROPERTYOPEN));
  183.       FFileName := aValue;
  184.    end;
  185. end;
  186.  
  187. {-- TMMMP3Encoder -------------------------------------------------------------}
  188. procedure TMMMp3Encoder.SetFileType(aValue: TMMFileType);
  189. begin
  190.    if (aValue <> FFileType) then
  191.    begin
  192.       if FOpen then
  193.          raise Exception.Create(LoadResStr(IDS_PROPERTYOPEN));
  194.       FFileType := aValue;
  195.    end;
  196. end;
  197.  
  198. {-- TMMMP3Encoder -------------------------------------------------------------}
  199. function TMMMP3Encoder._CreateFile;
  200. var
  201.    pwfx: PWaveFormatEx;
  202.  
  203. begin
  204.    if (FFileType = ftRAW) then
  205.    begin
  206.       FHandle := FileCreate(FFileName);
  207.       Result := (FHandle > 0);
  208.    end
  209.    else
  210.    begin
  211.       try
  212.          pwfx := acmBuildMP3Header(PWaveFormat.nSamplesPerSec, BR[FBitrate]*1000, PWaveFormat.nChannels);
  213.          try
  214.             FWave.CreateFile(FFileName,Pointer(pwfx));
  215.          finally
  216.             GlobalFreeMem(Pointer(pwfx));
  217.          end;
  218.          Result := True;
  219.       except
  220.          Result := False;
  221.       end;
  222.    end;
  223. end;
  224.  
  225. {-- TMMMP3Encoder -------------------------------------------------------------}
  226. procedure TMMMP3Encoder._CloseFile;
  227. begin
  228.    if (FFileType = ftRAW) then
  229.    begin
  230.       FileClose(FHandle);
  231.       FHandle := -1;
  232.    end
  233.    else
  234.    begin
  235.       FWave.CloseFile;
  236.       FWave.FreeWave;
  237.    end;
  238. end;
  239.  
  240. var
  241.    _GetDiskFreeSpaceEx: function (Directory: PChar; var FreeAvailable,
  242.                                   TotalSpace: Int64;
  243.                                   TotalFree: PInt64): Bool stdcall = nil;
  244.  
  245. { This function is used if the OS doesn't support GetDiskFreeSpaceEx }
  246. {-- TMMMP3Encoder -------------------------------------------------------------}
  247. function BackfillGetDiskFreeSpaceEx(Directory: PChar; var FreeAvailable,
  248.                                     TotalSpace: Int64;
  249.                                     TotalFree: PInt64): Bool; stdcall;
  250. var
  251.   SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters: DWORD;
  252.   Temp: Int64;
  253.   Dir : PChar;
  254. begin
  255.   if Directory <> nil then
  256.      Dir := PChar(ExtractFileDrive(Directory)+'\')
  257.   else
  258.      Dir := nil;
  259.  
  260.   Result := GetDiskFreeSpace(Dir, SectorsPerCluster, BytesPerSector,
  261.                               FreeClusters, TotalClusters);
  262.   Temp := SectorsPerCluster * BytesPerSector;
  263.   FreeAvailable := Temp * FreeClusters;
  264.   TotalSpace    := Temp * TotalClusters;
  265. end;
  266.  
  267. {-- TMMMP3Encoder -------------------------------------------------------------}
  268. function GetDiskStats(const Directory: string; var nFree, nSize: Int64): Boolean;
  269. begin
  270.    Result := _GetDiskFreeSpaceEx(PChar(ExtractFileDir(Directory)),nFree, nSize, nil);
  271.    if not Result then
  272.    begin { avoid errors from unchecked divisions }
  273.       nFree := 0;
  274.       nSize := 1;
  275.    end;
  276. end;
  277.  
  278. {-- TMMMP3Encoder -------------------------------------------------------------}
  279. function GetDiskFree(const Directory: string; nBytes: Longint): Boolean;
  280. var
  281.    nFree,nSize: Int64;
  282. begin
  283.    Result := False;
  284.    if GetDiskStats(Directory,nFree,nSize) then
  285.       Result := nFree >= nBytes;
  286. end;
  287.  
  288. {-- TMMMP3Encoder -------------------------------------------------------------}
  289. function TMMMP3Encoder._WriteFile(Buffer: PChar; nBytes: Longint): Boolean;
  290. begin
  291.    Result := GetDiskFree(FFileName,nBytes+10240);
  292.    if not Result then exit;
  293.  
  294.    if (FFileType = ftRAW) then
  295.    begin
  296.       Result := (FileWrite(FHandle,Buffer^,nBytes) = nBytes);
  297.    end
  298.    else
  299.    begin
  300.       Result := (FWave.WriteDataBytes(Buffer,nBytes) = nBytes);
  301.    end;
  302. end;
  303.  
  304. {-- TMMMP3Encoder -------------------------------------------------------------}
  305. procedure TMMMP3Encoder.Opened;
  306. var
  307.    Config: TBE_CONFIG;
  308. begin
  309.    inherited Opened;
  310.  
  311.    if not FOpen and (PWaveFormat <> nil) then
  312.    begin
  313.       if (Input <> nil) then
  314.       begin{ we are a Output port }
  315.  
  316.          { we should save anything to the file, create it }
  317.          if (FFileName <> '') then
  318.          begin
  319.             if not RequestDLLLoading then
  320.                 raise Exception.Create('Unable to load Blade Encoder DLL'#10#13+
  321.                                        'You can download the BladeEncoder at:'#10#13+
  322.                                        'http://home8.swipnet.se/~w-82625/encoder/binaries/BladeDLL075.zip');
  323.  
  324.             if (PWaveFormat.wFormatTag <> WAVE_FORMAT_PCM) or
  325.                (PWaveFormat.wBitsPerSample <> 16) or
  326.                ((PWaveFormat.nSamplesPerSec <> 48000) and
  327.                 (PWaveFormat.nSamplesPerSec <> 44100) and
  328.                 (PWaveFormat.nSamplesPerSec <> 32000)) then
  329.                 raise Exception.Create('Unsupported Input Format');
  330.  
  331.             with Config,Config.MP3 do
  332.             begin
  333.                dwConfig     := BE_CONFIG_MP3;
  334.                dwSampleRate := PWaveFormat.nSamplesPerSec;
  335.                if PWaveFormat.nChannels = 1 then
  336.                   byMode    := BE_MP3_MODE_MONO
  337.                else if (FChannelMode = cmMono) then
  338.                   bymode    := BE_MP3_MODE_STEREO
  339.                else
  340.                   byMode    := CM[Ord(FChannelMode)];
  341.                wBitrate     := BR[FBitrate];
  342.                bPrivate     := FPrivate;
  343.                bCRC         := FCRC;
  344.                bCopyright   := FCopyright;
  345.                bOriginal    := FOriginal;
  346.             end;
  347.  
  348.             DeleteFile(FFileName);
  349.             if not _CreateFile then
  350.                raise Exception.Create('Unable to create file');
  351.  
  352.             if (beInitStream(@Config,FInSamples,FOutBufSize,FHStream) <> 0) then
  353.                 raise Exception.Create('Unable to initialize stream');
  354.  
  355.             FInBufSize   := FInSamples*2;
  356.             FOutBuffer   := GlobalAllocMem(FOutBufSize);
  357.             FInBuffer    := GlobalAllocMem(FInBufSize);
  358.             FBytesQueued := 0;
  359.  
  360.             FOpen := True;
  361.          end;
  362.       end;
  363.    end;
  364. end;
  365.  
  366. {-- TMMMP3Encoder -------------------------------------------------------------}
  367. procedure TMMMP3Encoder.Closed;
  368. begin
  369.    if FOpen then
  370.    begin
  371.       Stopped;
  372.       _CloseFile;
  373.       if (FHStream <> 0) then
  374.       begin
  375.          beCloseStream(FHStream);
  376.          FHStream := 0;
  377.       end;
  378.       GlobalFreeMem(Pointer(FOutBuffer));
  379.       GlobalFreeMem(Pointer(FInBuffer));
  380.       FOpen := False;
  381.    end;
  382.  
  383.    inherited Closed;
  384. end;
  385.  
  386. {-- TMMMP3Encoder -------------------------------------------------------------}
  387. procedure TMMMP3Encoder.Started;
  388. begin
  389.    inherited Started;
  390.  
  391.    if not FStarted and FOpen then
  392.    begin
  393.       FStarted     := True;
  394.       FBytesQueued := 0;
  395.    end;
  396. end;
  397.  
  398. {-- TMMMP3Encoder -------------------------------------------------------------}
  399. procedure TMMMP3Encoder.Stopped;
  400. var
  401.    nEncoded: DWORD;
  402. begin
  403.    if FOpen and FStarted then
  404.    begin
  405.       FStarted := False;
  406.  
  407.       if (FBytesQueued > 0) then
  408.       begin
  409.          if (beEncodeChunk(FHStream, FBytesQueued div 2, FInBuffer, FOutBuffer, nEncoded) <> 0) then
  410.              raise Exception.Create('Unable to encode data');
  411.  
  412.          if (nEncoded > 0) then
  413.          begin
  414.             if not _WriteFile(FOutBuffer,nEncoded) then
  415.             begin
  416.                Closed;
  417.                exit;
  418.             end;
  419.          end;
  420.          dec(FBytesQueued,FInBufSize);
  421.       end;
  422.  
  423.       if (beDeinitStream(FHStream,FOutBuffer,nEncoded) <> 0) then
  424.           raise Exception.Create('Unable to deinitialize stream');
  425.  
  426.       if (nEncoded > 0) then
  427.       begin
  428.          if not _WriteFile(FOutBuffer,nEncoded) then
  429.          begin
  430.             Closed;
  431.             exit;
  432.          end;
  433.       end;
  434.    end;
  435.  
  436.    inherited Stopped;
  437. end;
  438.  
  439. {-- TMMMP3Encoder -------------------------------------------------------------}
  440. procedure TMMMP3Encoder.BufferReady(lpwh: PWaveHdr);
  441. var
  442.    n,nBytes,nRead,nEncoded: DWORD;
  443. begin
  444.    if FStarted and (Input <> nil) then
  445.    begin
  446.       { save the data to file (if any) }
  447.       if (FFileName <> '') and (lpwh^.dwBytesRecorded > 0) then
  448.       begin
  449.          nBytes := lpwh^.dwBytesRecorded;
  450.          nRead  := 0;
  451.  
  452.          if (FBytesQueued > 0) then
  453.          begin
  454.             n := Min(FInBufSize-FBytesQueued,nBytes);
  455.             Move(lpwh^.lpData^,(FInBuffer+FBytesQueued)^,n);
  456.             inc(FBytesQueued,n);
  457.  
  458.             inc(nRead,n);
  459.             dec(nBytes,n);
  460.  
  461.             if (FBytesQueued >= FInBufSize) then
  462.             begin
  463.                if (beEncodeChunk(FHStream, FInSamples, FInBuffer, FOutBuffer, nEncoded) <> 0) then
  464.                    raise Exception.Create('Unable to encode data');
  465.  
  466.                if (nEncoded > 0) then
  467.                begin
  468.                   if not _WriteFile(FOutBuffer,nEncoded) then
  469.                   begin
  470.                      Closed;
  471.                      exit;
  472.                   end;
  473.                end;
  474.                dec(FBytesQueued,FInBufSize);
  475.             end;
  476.          end;
  477.  
  478.          while (nBytes >= FInBufsize) do
  479.          begin
  480.             if (beEncodeChunk(FHStream, FInSamples, Pointer(lpwh^.lpData+nRead), FOutBuffer, nEncoded) <> 0) then
  481.                 raise Exception.Create('Unable to encode data');
  482.  
  483.             inc(nRead,FInBufSize);
  484.             dec(nBytes,FInBufSize);
  485.  
  486.             if (nEncoded > 0) then
  487.             begin
  488.                if not _WriteFile(FOutBuffer,nEncoded) then
  489.                begin
  490.                   Closed;
  491.                   exit;
  492.                end;
  493.             end;
  494.          end;
  495.  
  496.          if (nBytes > 0) then
  497.          begin
  498.             Move((lpwh^.lpData+nRead)^,FInBuffer^,nBytes);
  499.             FBytesQueued := nBytes;
  500.          end;
  501.       end;
  502.    end;
  503.  
  504.    inherited BufferReady(lpwh);
  505. end;
  506.  
  507. procedure InitDriveSpacePtr;
  508. var
  509.   Kernel: THandle;
  510. begin
  511.   Kernel := GetModuleHandle(Windows.Kernel32);
  512.   if Kernel <> 0 then
  513.      @_GetDiskFreeSpaceEx := GetProcAddress(Kernel, 'GetDiskFreeSpaceExA');
  514.  
  515.   if not Assigned(_GetDiskFreeSpaceEx) then
  516.      _GetDiskFreeSpaceEx := @BackfillGetDiskFreeSpaceEx;
  517. end;
  518.  
  519. initialization
  520.    InitDriveSpacePtr;
  521. end.
  522.